home *** CD-ROM | disk | FTP | other *** search
/ Delphi Informant Complete 1995 - 2000 / Delphi Informant Complete 1995 to 2000.iso / Delphi Informant Magazine Complete Works SOURCE CODE 1998.rar / 1998 / Mar / DI9803DM / common / AXPropBg.pas next >
Encoding:
Pascal/Delphi Source File  |  1997-10-12  |  7.6 KB  |  262 lines

  1. unit AXPropBg;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  7.   ActiveX, AxCtrls;
  8.  
  9. type
  10.   TActiveXPropBag = class(TActiveXControl, IPersistPropertyBag)
  11.   protected
  12.     { IPersistPropertyBag }
  13.     { Methods should be aliased so they don't collide with existing names }
  14.     function IPersistPropertyBag.InitNew = PersistPropBagInitNew;
  15.     function IPersistPropertyBag.Load = PersistPropBagLoad;
  16.     function IPersistPropertyBag.Save = PersistPropBagSave;
  17.     function PersistPropBagInitNew: HResult; stdcall;
  18.     function PersistPropBagLoad(const pPropBag: IPropertyBag;
  19.       const pErrorLog: IErrorLog): HResult; stdcall;
  20.     function PersistPropBagSave(const pPropBag: IPropertyBag; fClearDirty: BOOL;
  21.       fSaveAllProperties: BOOL): HResult; stdcall;
  22.   end;
  23.  
  24. implementation
  25.  
  26. uses
  27.   ComObj;
  28.  
  29. { Helper Methods }
  30.  
  31. const
  32.   DispIDArgs: Longint = DISPID_PROPERTYPUT;
  33.  
  34. function HandleException: HResult;
  35. var
  36.   E: TObject;
  37. begin
  38.   E := ExceptObject;
  39.   if (E is EOleSysError) and (EOleSysError(E).ErrorCode < 0) then
  40.     Result := EOleSysError(E).ErrorCode else
  41.     Result := E_UNEXPECTED;
  42. end;
  43.  
  44. { GetDispatchPropValue returns the value of the property associated with }
  45. { Disp's DispID. }
  46. function GetDispatchPropValue(Disp: IDispatch; DispID: Integer): OleVariant;
  47. var
  48.   ExcepInfo: TExcepInfo;
  49.   DispParams: TDispParams;
  50.   Status: HResult;
  51. begin
  52.   FillChar(DispParams, SizeOf(DispParams), 0);
  53.   Status := Disp.Invoke(DispID, GUID_NULL, 0, DISPATCH_PROPERTYGET, DispParams,
  54.     @Result, @ExcepInfo, nil);
  55.   if Status <> S_OK then DispatchInvokeError(Status, ExcepInfo);
  56. end;
  57.  
  58. { SetDispatchPropValue sets the value of the property associated with }
  59. { Disp's DispID. }
  60. procedure SetDispatchPropValue(Disp: IDispatch; DispID: Integer;
  61.   const Value: OleVariant);
  62. var
  63.   ExcepInfo: TExcepInfo;
  64.   DispParams: TDispParams;
  65.   Status: HResult;
  66. begin
  67.   with DispParams do
  68.   begin
  69.     rgvarg := @Value;
  70.     rgdispidNamedArgs := @DispIDArgs;
  71.     cArgs := 1;
  72.     cNamedArgs := 1;
  73.   end;
  74.   Status := Disp.Invoke(DispId, GUID_NULL, 0, DISPATCH_PROPERTYPUT, DispParams,
  75.     nil, @ExcepInfo, nil);
  76.   if Status <> S_OK then DispatchInvokeError(Status, ExcepInfo);
  77. end;
  78.  
  79. { EnumDispatchProperties fills a TStrings with property names and }
  80. { dispids for the properties of Dispatch.  You can use PropType and }
  81. { VTCode to filter for properties of a specific type, or you can pass }
  82. { GUID_NULL and VT_EMPTY respectively to get all properties. }
  83. procedure EnumDispatchProperties(Dispatch: IDispatch; PropType: TGUID;
  84.   VTCode: Integer; PropList: TStrings);
  85. const
  86.   INVOKE_PROPERTYSET = INVOKE_PROPERTYPUT or INVOKE_PROPERTYPUTREF;
  87. var
  88.   I: Integer;
  89.   TypeInfo: ITypeInfo;
  90.   TypeAttr: PTypeAttr;
  91.   FuncDesc: PFuncDesc;
  92.   VarDesc: PVarDesc;
  93.  
  94.   procedure SaveName(Id: Integer);
  95.   var
  96.     Name: WideString;
  97.   begin
  98.     OleCheck(TypeInfo.GetDocumentation(Id, @Name, nil, nil, nil));
  99.     if PropList.IndexOfObject(TObject(Id)) = -1 then
  100.       PropList.AddObject(Name, TObject(Id));
  101.   end;
  102.  
  103.   function IsPropType(const TypeInfo: ITypeInfo; TypeDesc: PTypeDesc): Boolean;
  104.   var
  105.     RefInfo: ITypeInfo;
  106.     RefAttr: PTypeAttr;
  107.     IsNullGuid: Boolean;
  108.   begin
  109.     IsNullGuid := IsEqualGuid(PropType, GUID_NULL);
  110.     Result := IsNullGuid and (VTCode = VT_EMPTY);
  111.     if Result then Exit;
  112.     case TypeDesc.vt of
  113.       VT_PTR: Result := IsPropType(TypeInfo, TypeDesc.ptdesc);
  114.       VT_USERDEFINED:
  115.         begin
  116.           OleCheck(TypeInfo.GetRefTypeInfo(TypeDesc.hreftype, RefInfo));
  117.           OleCheck(RefInfo.GetTypeAttr(RefAttr));
  118.           try
  119.             Result := IsEqualGUID(RefAttr.guid, PropType);
  120.             if not Result and (RefAttr.typekind = TKIND_ALIAS) then
  121.               Result := IsPropType(RefInfo, @RefAttr.tdescAlias);
  122.           finally
  123.             RefInfo.ReleaseTypeAttr(RefAttr);
  124.           end;
  125.         end;
  126.     else
  127.       Result := IsNullGuid and (TypeDesc.vt = VTCode);
  128.     end;
  129.   end;
  130.  
  131.   function HasMember(const TypeInfo: ITypeInfo; Cnt, MemID, InvKind: Integer): Boolean;
  132.   var
  133.     I: Integer;
  134.     FuncDesc: PFuncDesc;
  135.   begin
  136.     for I := 0 to Cnt - 1 do
  137.     begin
  138.       OleCheck(TypeInfo.GetFuncDesc(I, FuncDesc));
  139.       try
  140.         if (FuncDesc.memid = MemID) and (FuncDesc.invkind and InvKind <> 0) then
  141.         begin
  142.           Result := True;
  143.           Exit;
  144.         end;
  145.       finally
  146.         TypeInfo.ReleaseFuncDesc(FuncDesc);
  147.       end;
  148.     end;
  149.     Result := False;
  150.   end;
  151.  
  152. begin
  153.   OleCheck(Dispatch.GetTypeInfo(0,0,TypeInfo));
  154.   if TypeInfo = nil then Exit;
  155.   OleCheck(TypeInfo.GetTypeAttr(TypeAttr));
  156.   try
  157.     for I := 0 to TypeAttr.cVars - 1 do
  158.     begin
  159.       OleCheck(TypeInfo.GetVarDesc(I, VarDesc));
  160.       try
  161.         if (VarDesc.wVarFlags and VARFLAG_FREADONLY <> 0) and
  162.           IsPropType(TypeInfo, @VarDesc.elemdescVar.tdesc) then
  163.           SaveName(VarDesc.memid);
  164.       finally
  165.         TypeInfo.ReleaseVarDesc(VarDesc);
  166.       end;
  167.     end;
  168.     for I := 0 to TypeAttr.cFuncs - 1 do
  169.     begin
  170.       OleCheck(TypeInfo.GetFuncDesc(I, FuncDesc));
  171.       try
  172.         if ((FuncDesc.invkind = INVOKE_PROPERTYGET) and
  173.           HasMember(TypeInfo, TypeAttr.cFuncs, FuncDesc.memid, INVOKE_PROPERTYSET) and
  174.           IsPropType(TypeInfo, @FuncDesc.elemdescFunc.tdesc)) or
  175.           ((FuncDesc.invkind and INVOKE_PROPERTYSET <> 0) and
  176.           HasMember(TypeInfo, TypeAttr.cFuncs, FuncDesc.memid, INVOKE_PROPERTYGET) and
  177.           IsPropType(TypeInfo,
  178.             @FuncDesc.lprgelemdescParam[FuncDesc.cParams - 1].tdesc)) then
  179.             SaveName(FuncDesc.memid);
  180.       finally
  181.         TypeInfo.ReleaseFuncDesc(FuncDesc);
  182.       end;
  183.     end;
  184.   finally
  185.     TypeInfo.ReleaseTypeAttr(TypeAttr);
  186.   end;
  187. end;
  188.  
  189. { TActiveXPropBag.IPersistPropertyBag }
  190. function TActiveXPropBag.PersistPropBagInitNew: HResult;
  191. begin
  192.   // NOTE: A return value of E_NOTIMPL is not allowed.  You must return S_OK
  193.   // even if this method does nothing.
  194.   Result := S_OK;
  195. end;
  196.  
  197. function TActiveXPropBag.PersistPropBagLoad(const pPropBag: IPropertyBag;
  198.   const pErrorLog: IErrorLog): HResult;
  199. var
  200.   PropList: TStringList;
  201.   i: Integer;
  202.   WPropName: WideString;
  203.   PropValue: OleVariant;
  204. begin
  205.   try
  206.     if pPropBag = nil then
  207.     begin
  208.       Result := E_POINTER;
  209.       Exit;
  210.     end;
  211.     Result := S_OK;
  212.     PropList := TStringList.Create;
  213.     try
  214.       EnumDispatchProperties(Self as IDispatch, GUID_NULL, VT_EMPTY, PropList);
  215.       for i := 0 to PropList.Count - 1 do
  216.       begin
  217.         WPropName := PropList[i];
  218.         if pPropBag.Read(PWideChar(WPropName), PropValue, pErrorLog) = S_OK then
  219.           SetDispatchPropValue(Self as IDispatch, Integer(PropList.Objects[i]),
  220.             PropValue);
  221.       end;
  222.     finally
  223.       PropList.Free;
  224.     end;
  225.   except
  226.     Result := HandleException;
  227.   end;
  228. end;
  229.  
  230. function TActiveXPropBag.PersistPropBagSave(const pPropBag: IPropertyBag;
  231.   fClearDirty: BOOL; fSaveAllProperties: BOOL): HResult;
  232. var
  233.   PropList: TStringList;
  234.   i: Integer;
  235.   WPropName: WideString;
  236. begin
  237.   try
  238.     if pPropBag = nil then
  239.     begin
  240.       Result := E_POINTER;
  241.       Exit;
  242.     end;
  243.     Result := S_OK;
  244.     PropList := TStringList.Create;
  245.     try
  246.       EnumDispatchProperties(Self as IDispatch, GUID_NULL, VT_EMPTY, PropList);
  247.       for i := 0 to PropList.Count - 1 do
  248.       begin
  249.         WPropName := PropList[i];
  250.         pPropBag.Write(PWideChar(WPropName),
  251.           GetDispatchPropValue(Self as IDispatch, Integer(PropList.Objects[i])));
  252.       end;
  253.     finally
  254.       PropList.Free;
  255.     end;
  256.   except
  257.     Result := HandleException;
  258.   end;
  259. end;
  260.  
  261. end.
  262.